#include "ws2812.h"

static IoT_SPI_InitTypeDef g_spi_cfg =
    {
        .Mode              = SPI_MODE_MASTER,
        .Direction         = SPI_DIRECTION_1LINE_TX,
        .DataSize          = SPI_DATASIZE_8BIT,
        .CLKPolarity       = SPI_POLARITY_LOW,
        .CLKPhase          = SPI_PHASE_2EDGE,
        .BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16,
        .FirstBit          = SPI_FIRSTBIT_MSB,
};

static u8_buf g_spi_buf[WS2812_LED_NUM];
static uint32_t g_spi_id;

static float __getMaxValue(float a, float b)
{
    return a >= b ? a : b;
}
static float __getMinValue(float a, float b)
{
    return a <= b ? a : b;
}

static void rgb_2_hsv(RGB_Color RGB, HSV_Color *HSV)
{
    float r, g, b, minRGB, maxRGB, deltaRGB;

    r        = RGB.R / 255.0f;
    g        = RGB.G / 255.0f;
    b        = RGB.B / 255.0f;
    maxRGB   = __getMaxValue(r, __getMaxValue(g, b));
    minRGB   = __getMinValue(r, __getMinValue(g, b));
    deltaRGB = maxRGB - minRGB;

    HSV->V = maxRGB;
    if (HSV->V != 0.0f) {
        HSV->S = deltaRGB / HSV->V;
    } else {
        HSV->S = 0.0f;
    }

    if (HSV->S <= 0.0f) {
        HSV->H = 0.0f;
    } else {
        if (HSV->V == r) {
            HSV->H = (g - b) / deltaRGB;
        } else if (HSV->V == g) {
            HSV->H = 2.0f + (b - r) / deltaRGB;
        } else if (HSV->V == b) {
            HSV->H = 4.0f + (r - g) / deltaRGB;
        }

        HSV->H = HSV->H * 60.0f;
        if (HSV->H < 0.0f) {
            HSV->H += 360;
        }
        HSV->H /= 360;
    }
}

static void hsv_2_rgb(HSV_Color HSV, RGB_Color *RGB)
{
    int hi;
    float R, G, B, p, q, t, f;

    if (HSV.S <= 0.0f) {
        R = G = B = HSV.V;
    } else {
        if (HSV.H == 1.0f) {
            HSV.H = 0.0f;
        }
        HSV.H *= 6.0f;
        hi = (int)HSV.H; // floor()
        f  = HSV.H - hi;
        p  = HSV.V * (1.0f - HSV.S);
        q  = HSV.V * (1.0f - HSV.S * f);
        t  = HSV.V * (1.0f - (HSV.S * (1.0f - f)));
        switch (hi) {
            case 0:
                R = HSV.V;
                G = t;
                B = p;
                break;
            case 1:
                R = q;
                G = HSV.V;
                B = p;
                break;
            case 2:
                R = p;
                G = HSV.V;
                B = t;
                break;
            case 3:
                R = p;
                G = q;
                B = HSV.V;
                break;
            case 4:
                R = t;
                G = p;
                B = HSV.V;
                break;
            case 5:
                R = HSV.V;
                G = p;
                B = q;
                break;
        }
    }
    RGB->R = (unsigned char)(R * 255);
    RGB->G = (unsigned char)(G * 255);
    RGB->B = (unsigned char)(B * 255);
}
static void brightness_adjust(float percent, RGB_Color in, RGB_Color *out)
{
    HSV_Color hsv_color;

    if (percent < 0.01f) {
        percent = 0.01f;
    }
    if (percent > 1.0f) {
        percent = 1.0f;
    }
    rgb_2_hsv(in, &hsv_color);
    hsv_color.V = percent;
    hsv_2_rgb(hsv_color, out);
}
static void ws281x_spi_io_init(enum EnumSpiId id)
{
    g_spi_id = id;
    IoTSpiDeinit(id);
    IoTSpiInit(id, &g_spi_cfg);
}

static void ws281x_spi_buf_refresh(void)
{
    IoTSpiWrite(g_spi_id, (uint8_t *)g_spi_buf, sizeof(g_spi_buf));
}

void ws281x_set_pixel_rgb(uint16_t x, uint16_t y, uint32_t rgb_color, float brightness)
{
    rgb888_32_u rgb_color_in  = {.v32 = rgb_color};
    rgb888_32_u rgb_color_out = {0};
    uint32_t index            = x + y * WS2812_LED_X_MAX;

    if (x < WS2812_LED_X_MAX && y < WS2812_LED_Y_MAX && index < WS2812_LED_NUM) {
        brightness_adjust(brightness, rgb_color_in.v8, &rgb_color_out.v8);
        uint32_t send_data = rgb_color_out.v32;
        for (int i = 0; i < SPI_DATA_BIT_WIDE; ++i) {
#if SPI_DATA_BIT_WIDE == 12
            g_spi_buf[index][i] = (((send_data << (i * 2)) & 0X800000) ? SIG_1 << 4 : SIG_0 << 4) |
                                  (((send_data << (i * 2 + 1)) & 0X800000) ? SIG_1 : SIG_0);
#elif SPI_DATA_BIT_WIDE == 24
            g_spi_buf[index][i] = (((send_data << i) & 0X800000) ? SIG_1 : SIG_0);
#endif
        }
        ws281x_spi_buf_refresh();
    }
}

void ws2812x_set_light_sta(int light_cnt, bool sta)
{
    if (light_cnt < 0 || light_cnt > WS2812_LED_NUM) {
        return;
    }

    uint32_t color = 0xFFFFFF; // 白光
    float brightness = sta ? 1.0f : 0.0f;
    printf("Setting WS2812 light state to %s\n", sta ? "ON" : "OFF");
    for (int i = 0; i < light_cnt; i++) {
        ws281x_set_pixel_rgb(i, 0, color, brightness);
        LOS_Msleep(50); // 延时50ms，确保每个LED有足够的时间更新
    }
}
void ws281x_init(enum EnumSpiId id)
{
    ws281x_spi_io_init(id);
}
